package com.cloud.ebookreader.opf;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import com.cloud.ebookreader.access.Book;
import com.cloud.ebookreader.access.Component;
import com.cloud.ebookreader.access.Metadata;
import com.cloud.ebookreader.access.TocEntry;

public class OcfEpubBook implements Book{
	Map<String, Component> components = new HashMap<String, Component>();
    List<TocEntry> toc = new LinkedList<TocEntry>();
    Metadata metadata;
    
    final Logger logger = Logger.getLogger(this.getClass());
    
    public OcfEpubBook(InputStream epub) throws IOException, SAXException{
        ZipInputStream zip = new ZipInputStream(epub);
        
        ZipEntry entry = null;
        while( (entry = zip.getNextEntry() ) != null){
            components.put(entry.getName(), new InMemoryComponent(entry.getName(), zip) );
            zip.closeEntry();
        }
        parseToc();
    }
    
    private void parseToc() throws SAXException, IOException{
        Component container = components.get("META-INF/container.xml");
        
        Component rootFile = getRootFile(container);
        
        logger.info("Root File is "+rootFile);
        
        OpfParser parser = new OpfParser();
        parser.parse(rootFile.getContent());
        
        this.metadata = parser.getMetadata();
        
        this.toc = parser.getToc();
        
        for(String key : parser.getMime().keySet()){
            Component comp = components.get(key);
            comp.setMime(parser.getMime().get(key));
        }
        
        for(TocEntry entry : parser.getToc()){
            entry.setComponentName(entry.getComponentName());
        }
        
    }

    public Component getComponent(String id) {
        if(components.containsKey(id)){
            return components.get(id);
        }else{
            return searchComponent(id);
        }
    }

    public List<TocEntry> getToc() {
        return toc;
    }

    public Metadata getMetadata() {
        return metadata;
    }

    private Component getRootFile(Component container) throws SAXException, IOException {
        XMLReader xmlReader = XMLReaderFactory.createXMLReader();
        final InMemoryComponent root = new InMemoryComponent() ;
        xmlReader.setContentHandler(new ContentHandler() {

            public void setDocumentLocator(Locator lctr) {
               
            }

            public void startDocument() throws SAXException {
               
            }

            public void endDocument() throws SAXException {
               
            }

            public void startPrefixMapping(String string, String string1) throws SAXException {
               
            }

            public void endPrefixMapping(String string) throws SAXException {
               
            }

            public void startElement(String string, String localName, String string2, Attributes atrbts) throws SAXException {
               if(localName.equals("rootfile")){
                   logger.debug("Found Rootname");
                   root.setName(atrbts.getValue("full-path"));
               }
            }

            public void endElement(String string, String string1, String string2) throws SAXException {
               
            }

            public void characters(char[] chars, int i, int i1) throws SAXException {
               
            }

            public void ignorableWhitespace(char[] chars, int i, int i1) throws SAXException {
               
            }

            public void processingInstruction(String string, String string1) throws SAXException {
               
            }

            public void skippedEntity(String string) throws SAXException {
               
            }
        });
        xmlReader.parse(new InputSource(container.getContent()));
        return components.get(root.getName());
    }

    private Component searchComponent(String id) {
        for(String k : components.keySet()){
            if(k.endsWith(id))
                return components.get(k);
        }
        return null;
    }
}
